using IQIGame.Onigao.Framework;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    [ExecuteAlways]
    //[RequireComponent(typeof(Rigidbody))]
    public class MaterialChangeRegion : MonoBehaviour, IBetterPrioritizElement
    {
        #region 声明类型
        /// <summary>
        /// 如果有需要可以继续加
        /// </summary>
        public enum MatChangeTimeType
        {
            None = 0,
            Night = 1,      //夜晚
            Day = 2,        //白天
        }

        public enum MatChangeValueType
        {
            Float = 1,
        }

        [System.Serializable]
        public class MatChangeValue
        {
            public MatChangeTimeType timeType = MatChangeTimeType.Night;
            public string name;
            public MatChangeValueType valueType = MatChangeValueType.Float;
            public float floatValue;
        }

        #endregion

        #region 序列化数据

#if UNITY_EDITOR
        [Sirenix.OdinInspector.LabelText("做检测的层")]
#endif
        /// <summary>
        /// 做检测的层
        /// </summary>
        public LayerMask checkLayerMask = (1 << (int)LayerConsts.Character) | (1 << (int)LayerConsts.Entity);

#if UNITY_EDITOR
        [Sirenix.OdinInspector.LabelText("检测的优先级(重叠的情况)(大的优先)")]
#endif
        [SerializeField]
        private int _priority = 0;
        public int priority
        {
            get => _priority;
            set => _priority = value;
        }

#if UNITY_EDITOR
        [Sirenix.OdinInspector.LabelText("忽略时间改变(只用列表第一个,适合固定时间情景)")]
#endif
        public bool ignoreChangedTime;


#if UNITY_EDITOR
        [Sirenix.OdinInspector.LabelText("材质修改数据")]
#endif
        public MatChangeValue[] matChangeValues;

        #endregion

        #region 全局数据
        /// <summary>
        /// 全局时间
        /// </summary>
        public static MatChangeTimeType globalTime { private set; get; } = MatChangeTimeType.Night;

        private static event Action changeTimeEvent;

        public static void InvokeChangeTime(MatChangeTimeType timeType)
        {
            if (globalTime == timeType)
            {
                return;
            }
            globalTime = timeType;
            changeTimeEvent?.Invoke();
        }

        #endregion

        #region Trigger碰撞检测 & Mono

        private HashSet<IMaterialChangeable> materialChangeables = new HashSet<IMaterialChangeable>();

        private Action<IMaterialChangeable> onMatChangeableDestroy;

        private void Awake()
        {
            if (!ignoreChangedTime)
            {
                changeTimeEvent += OnChangeGlobalTime;
            }

            onMatChangeableDestroy = MatChangeableDestroy;
        }

        private void OnDestroy()
        {
            changeTimeEvent -= OnChangeGlobalTime;
        }

        private void OnChangeGlobalTime()
        {
            foreach (var v in materialChangeables)
            {
                if (v == null)
                {
                    continue;
                }
                v.RefreshMatRegion(this);
            }
        }

        public void OnTriggerEnter(Collider other)
        {
            if (other == null || ((1 << other.gameObject.layer) & checkLayerMask) == 0)
            {
                return;
            }
            var matChangeable = other.GetComponent<IMaterialChangeable>();
            if (matChangeable != null && matChangeable.AddMatChangeRegion(this))
            {
                materialChangeables.Add(matChangeable);
                matChangeable.RegisterDestroyEvent(this.onMatChangeableDestroy);
            }
        }

        public void OnTriggerExit(Collider other)
        {
            if (other == null || ((1 << other.gameObject.layer) & checkLayerMask) == 0)
            {
                return;
            }
            var matChangeable = other.GetComponent<IMaterialChangeable>();
            if (matChangeable != null && matChangeable.RemoveMatChangeRegion(this))
            {
                materialChangeables.Remove(matChangeable);
                matChangeable.UnRegisterDestroyEvent(this.onMatChangeableDestroy);
            }
        }

        private void MatChangeableDestroy(IMaterialChangeable changeable)
        {
            materialChangeables.Remove(changeable);
        }

        #endregion

        #region 公开接口
        public bool ChangeMaterialValue(IMaterialChangeable materialChangeable)
        {
            if (materialChangeable == null)
            {
                return false;
            }
            if (matChangeValues.Length == 0)
            {
                return false;
            }
            if (ignoreChangedTime)
            {
                // 忽略时间，只会用第一个
                ChangeMatValueInternal(materialChangeable, matChangeValues[0]);
                return true;
            }
            for (int i = 0; i < matChangeValues.Length; i++)
            {
                var mv = matChangeValues[i];
                if (mv.timeType == globalTime)
                {
                    ChangeMatValueInternal(materialChangeable, mv);
                    return true;
                }
            }
            return false;
        }

        private void ChangeMatValueInternal(IMaterialChangeable materialChangeable, MatChangeValue mv)
        {
            switch (mv.valueType)
            {
                case MatChangeValueType.Float:
                    LogGame.Log($"[区域设置材质球] {materialChangeable.debugName}->({mv.name} = {mv.floatValue})");
                    materialChangeable.MatSetFloat(mv.name, mv.floatValue);
                    break;
            }
        }
        #endregion

    }
}
